import { useNavigate } from 'react-router-dom';
import { App } from 'antd';
import { LoginParams } from '@/api/services/userServices.ts';
import { createJSONStorage, persist } from 'zustand/middleware';
import { shallow } from 'zustand/shallow';
import UserServices from '@/api/services/userServices.ts';
import { flattenPermission } from '@/utils';
import { createWithEqualityFn } from 'zustand/traditional';
import { RoleInfo } from '#/entity.ts';

interface UserInfo {
  id?: number;
  userName?: string;
  realName?: string;
  phone?: string;
  companyId?: number;
  companyName?: string;
  token?: string;
  roleList?: RoleInfo[];
  headImage?: string;
  resetPassword?: boolean;
}

// https://github.com/pmndrs/zustand/tree/2b29d736841dc7b3fd7dec8cbfea50fee7295974#selecting-multiple-state-slices
interface UserStore {
  userInfo: UserInfo;
  permissions: string[];
  actions: () => {
    setUserInfo: (userInfo: UserInfo) => void;
    setPermissions: (permissions: string[]) => void;
    clearUserInfo: () => void;
  };
}

const DEFAULT_USER_INFO: UserInfo = {};

const userInfo = persist<UserStore>(
  (set) => ({
    userInfo: DEFAULT_USER_INFO,
    permissions: [],
    actions: () => ({
      setUserInfo: (userInfo) => set({ userInfo }),
      setPermissions: (permissions) => set({ permissions }),
      clearUserInfo: () => set({ userInfo: DEFAULT_USER_INFO }),
    }),
  }),
  {
    name: 'userInfo',
    storage: createJSONStorage(() => localStorage),
    // https://zustand.docs.pmnd.rs/integrations/persisting-store-data#version
    version: 0,
  },
);

// why use shallow? https://zustand.docs.pmnd.rs/apis/shallow
// why use createWithEqualityFn? https://github.com/pmndrs/zustand/discussions/1937
const userStore = createWithEqualityFn(userInfo, shallow);

export const useUserInfo = () => userStore((state) => state.userInfo);
export const useUserId = () => userStore((state) => state.userInfo.id);
export const useUserToken = () => userStore((state) => state.userInfo.token);
export const usePermissions = () => userStore((state) => state.permissions ?? []);
export const useRoleList = () => userStore((state) => state.userInfo.roleList ?? []);
export const useUserActions = () => userStore((state) => state.actions());

const HOME_PAGE = '/event-center';

export const useLogin = () => {
  const navigatge = useNavigate();
  const { message } = App.useApp();

  const { setUserInfo, setPermissions } = useUserActions();

  return async (params: LoginParams, redirect: string | null) => {
    try {
      const { data } = await UserServices.login(params);
      const {
        id,
        userName,
        realName,
        phone,
        companyId,
        companyName,
        roleList,
        token,
        headImage,
        resetPassword,
      } = data;
      let permissions: string[] = [];
      roleList.forEach((role) => {
        role.menuVoList.forEach((menu) => {
          permissions.push(menu.menuPath);
        });
      });
      permissions = Array.from(new Set(permissions));
      setUserInfo({
        id,
        userName,
        realName,
        phone,
        companyId,
        companyName,
        token,
        roleList,
        headImage,
        resetPassword,
      });
      setPermissions(permissions);
      navigatge(redirect ?? HOME_PAGE, { replace: true });
    } catch (err) {
      message.error(err.message);
    }
  };
};

export const useRefreshUserInfo = () => {
  const { message } = App.useApp();

  const { setUserInfo, setPermissions } = useUserActions();

  return async () => {
    try {
      const { data } = await UserServices.getUserInfo();
      const {
        id,
        userName,
        realName,
        phone,
        companyId,
        companyName,
        roleList,
        token,
        headImage,
        resetPassword,
      } = data;
      const permissions = Array.from(
        new Set(flattenPermission(roleList.flatMap((i) => i.menuVoList))),
      );
      setUserInfo({
        id,
        userName,
        realName,
        phone,
        companyId,
        companyName,
        token,
        roleList,
        headImage,
        resetPassword,
      });
      setPermissions(permissions);
      return data;
    } catch (e) {
      message.error(e.message);
      throw new Error(e);
    }
  };
};

export const useLogout = () => {
  const navigatge = useNavigate();
  const { message } = App.useApp();

  const { clearUserInfo } = useUserActions();

  return async () => {
    try {
      clearUserInfo();
      navigatge('/login', { replace: true });
    } catch (err) {
      message.error(err.message);
    }
  };
};

export default userStore;
